﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Text.RegularExpressions;
using AbstraX.ServerInterfaces;
using System.ServiceModel.DomainServices.Server;
using System.ComponentModel.DataAnnotations;
using AbstraX.XPathBuilder;
using System.Runtime.Serialization;
using MvvmTreeView;
using System.Diagnostics;
using AbstraX.Templates;
using AbstraX;
using AbstraX.TypeMappings;
using AbstraX.Contracts;


namespace EntityProvider.Web.Entities
{
    [DataContract, NodeImage("EntityProvider.Web.Images.Entity.png"), DebuggerDisplay("{ DebugInfo }"), ClientCodeGeneration(typeof(AbstraXClientInterfaceGenerator))]
    public class EntityType : EntitiesBase, IElement
    {
        private string name;
        private XmlNode node;
        private string queryWhereProperty;
        private object queryWhereValue;
        private IEntityParent parent;

        public EntityType()
        {
        }

        public EntityType(XmlDocument edmxDocument, XmlNamespaceManager namespaceManager, string name, XmlNode node, IEntityParent parent)
        {
            this.EdmxDocument = edmxDocument;
            this.NamespaceManager = namespaceManager;
            this.name = name;
            this.node = node;
            this.parent = parent;
        }
        [AbstraXExtensionAttribute("IEntityProviderExtension", "EntityProviderExtension")]
        public IAbstraXExtension LoadExtension()
        {
            return null;
        }
        [Exclude()]
        public XmlNode Node
        {
            get 
            { 
                return node; 
            }
        }

        [Association("Entity_EntityProperties", "ID", "ParentID")]
        public List<EntityProperty> Properties
        {
            get
            {
                var properties = new List<EntityProperty>();

                foreach (XmlNode attributeNode in node.SelectNodes("e:Property", this.NamespaceManager))
                {
                    var name = attributeNode.Attributes["Name"].Value;

                    properties.Add(new EntityProperty(this.EdmxDocument, this.NamespaceManager, name, attributeNode, this));
                }

                return properties;
            }
        }

        public IEnumerable<IAttribute> Attributes
        {
            get 
            {
                var attributes = this.Properties.AsQueryable().Cast<IAttribute>().Select(e => e);

                return attributes;
            }
        }

        [Association("Entity_NavigationProperties", "ID", "ParentID")]
        public List<NavigationProperty> NavigationProperties
        {
            get
            {
                var properties = new List<NavigationProperty>();

                if (queryWhereProperty != null && queryWhereProperty == "Property")
                {
                    var property = node.SelectSingleNode("e:NavigationProperty[@Name='" + (string) queryWhereValue + "']", this.NamespaceManager);
                    var name = property.Attributes["Name"].Value;

                    Debug.Assert(property != null);

                    properties.Add(new NavigationProperty(this.EdmxDocument, this.NamespaceManager, name, property, this));
                }
                else
                {
                    foreach (XmlNode childNode in node.SelectNodes("e:NavigationProperty", this.NamespaceManager))
                    {
                        var name = childNode.Attributes["Name"].Value;

                        properties.Add(new NavigationProperty(this.EdmxDocument, this.NamespaceManager, name, childNode, this));
                    }
                }

                return properties;
            }
        }

        public IEnumerable<IElement> ChildElements
        {
            get 
            {
                var elements = this.NavigationProperties.AsQueryable().Cast<IElement>().Select(e => e);

                return elements;
            }
        }

        public IEnumerable<IOperation> Operations
        {
            get { return null; }
        }

        [DataMember, Key]
        public string ID
        {
            get
            {
                return this.MakeID("Entity='" + name + "'");
            }
        }

        [DataMember]
        public string ParentID
        {
            get
            {
                return parent.ID;
            }
        }

        [DataMember]
        public string Name
        {
            get 
            {
                return name;
            }
        }

        [DataMember]
        public string ImageURL
        {
            get
            {
                return string.Empty;
            }
        }

        [DataMember]
        public bool IsContainer
        {
            get
            {
                return false;
            }
        }

        [Include, Association("Parent_BaseType", "ID", "ParentID")]
        public BaseType DataType
        {
            get
            {
                string _namespace = null;
                var parent = this.Parent;

                while (parent != null)
                {
                    if (parent is Project)
                    {
                        var project = (Project)parent;
                        _namespace = project.DefaultNamespace;

                        break;
                    }

                    parent = parent.Parent;
                }

                return new BaseType
                {
                    FullyQualifiedName = _namespace + "." + name,
                    Name = name,
                    ID = name,
                    ParentID = this.ID
                };
            }
        }

        public void ExecuteWhere(string property, object value)
        {
            if (value is XPathAxisElement && (property == "ID" || property == "ParentID"))
            {
                var predicate = ((XPathAxisElement)value).Predicates.First();

                queryWhereProperty = predicate.Left;
                queryWhereValue = predicate.Right;
            }
            else
            {
                System.Diagnostics.Debugger.Break();

                queryWhereProperty = property;
                queryWhereValue = value;
            }
        }

        public void ExecuteWhere(System.Linq.Expressions.Expression expression)
        {
        }

        public void ExecuteWhere(XPathAxisElement element)
        {
            var predicate = element.Predicates.First();

            queryWhereProperty = predicate.Left;
            queryWhereValue = predicate.Right;
        }

        public void ClearPredicates()
        {
            queryWhereProperty = null;
            queryWhereValue = null;
        }

        public IRoot Root
        {
            get
            {
                IBase baseObject = this;

                while (baseObject != null)
                {
                    baseObject = baseObject.Parent;

                    if (baseObject is IRoot)
                    {
                        return (IRoot)baseObject;
                    }
                }

                return null;
            }
        }


        [DataMember]
        public string Description
        {
            get { return string.Empty; }
        }

        [DataMember]
        public string Documentation
        {
            get { return string.Empty; }
        }

        [DataMember]
        public float ChildOrdinal
        {
            get
            {
                return 0;
            }
        }

        [DataMember]
        public string DebugInfo
        {
            get
            {
                return name + ":" + ID;
            }
        }

        public IBase Parent
        {
            get
            {
                return this.parent;
            }
        }

        [DataMember]
        public string FolderKeyPair { get; set; }

        [DataMember]
        public DefinitionKind Kind
        {
            get
            {
                return DefinitionKind.NotApplicable;
            }
        }

        [DataMember]
        public bool HasChildren
        {
            get
            {
                if (this.Properties.Any())
                {
                    return true;
                }
                else if (this.NavigationProperties.Any())
                {
                    return true;
                }

                return false;
            }
        }

        [DataMember, Include, Association("Parent_Facet", "ID", "ParentID")]
        public Facet[] Facets
        {
            get
            {
                return null;
            }
        }

        [Exclude]
        public ContainerType AllowableContainerTypes
        {
            get { throw new NotImplementedException(); }
        }

        [Exclude]
        public ConstructType AllowableConstructTypes
        {
            get { throw new NotImplementedException(); }
        }

        [Exclude]
        public ContainerType DefaultContainerType
        {
            get { throw new NotImplementedException(); }
        }

        [Exclude]
        public ConstructType DefaultConstructType
        {
            get { throw new NotImplementedException(); }
        }
    }
}
